/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

#ifndef __dylab_ComponentBase_h__
#define __dylab_ComponentBase_h__

//===========================================================================================
#include <dylab/utils/thread/GuardedObject.h>
#include <dylab/utils/components/ComponentManager.h>
#include <dylab/utils/EntityDefinitionManager.h>

//===========================================================================================
namespace dylab {

    // the derived classes inherits getName & getFullName from ComponentBase - no problem
#   if defined(DYLAB_COMPILER_MSVC)
#       pragma warning (disable : 4250)
#   endif

    /** 
     * Base class for all component classes.
     */
    template <
        class _ComponentTypeT
    >
    class ComponentBase 
        : virtual public IComponent
		, public EntityDefinitionManager::EntityBase<_ComponentTypeT>
    {
    public:
        class DYLAB_EXPORT Instance 
            : public GuardedObject<_ComponentTypeT>
        {
        public:
            Instance()
                : GuardedObject<_ComponentTypeT>()
                    { }
            Instance(_ComponentTypeT * _component)
                : GuardedObject<_ComponentTypeT>(_component)
                    { }
            Instance & operator = (_ComponentTypeT * _component)
                    {  assign(_component); return *this; }
        };        
        typedef typename Instance::ScopedShLock ScopedShLock;
        typedef typename Instance::ScopedExLock ScopedExLock;
        //-----------------------------------------------------------------------------      

    public:
		/// returns the identification string for the current component class (given by the template param)
        static String getComponentTypeId()
                { return typeid(_ComponentTypeT).raw_name(); }

		/// returns the full component name (class and name) using the component manager singleton
        static String getComponentFullName(const String & _compName)
                { return DYLAB_SINGLETON_SCOPED_SH_LOCK(ComponentManager)->
					getComponentFullName(getComponentTypeId(), _compName); }

		/// registers the component class (given by the template param) with the specified name
        static void registerComponentType(const String & _compTypeName)
			{ DYLAB_SINGLETON_SCOPED_EX_LOCK(ComponentManager)->
				registerComponentType(getComponentTypeId(), _compTypeName); }

		/// create new component according to its class (template param) and name (method param)
        static _ComponentTypeT * create(const String & _compName)
                { return dynamicCast<_ComponentTypeT>(DYLAB_SINGLETON_SCOPED_EX_LOCK(ComponentManager)->
					createComponent(getComponentFullName(_compName))); }

		/// loads the given component from data in the specified property tree
		static void loadComFromPropertyTree(Instance * _compInstance, const PropertyTree & _pt)
				{ ScopedExLock(_compInstance)->loadFromPropertyTree(_pt); }

    private:
        // the component's name
        String mName;

    public:

		/**
		 * Every componet has to have a name.
		 */
        ComponentBase(const String & _name)
            : mName(_name)
                { }

        virtual String getName() const
                { return mName; }
        virtual String getDescription() const
                { return getFullName(); }
        virtual String getFullName() const
                { return getComponentFullName(getName()); }
    };
}

//===========================================================================================
#endif // __dylab_ComponentBase_h__
